﻿/* Copyright (c) 2010, John Cronin
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the copyright holder nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

using System;
using System.Collections.Generic;
using System.Text;

namespace tysila
{
    partial class Layout
    {
        public List<ImplementedInterface> Interfaces = new List<ImplementedInterface>();
        Assembler _ass;
        Assembler.TypeToCompile _ttc; public Assembler.TypeToCompile Type { get { return _ttc; } }

        int class_size; public int ClassSize { get { return class_size; } }
        int vtbl_size; public int VTableSize { get { return vtbl_size; } }
        int static_size; public int StaticClassSize { get { return static_size; } }
        string ti_name; public string TypeInfoMangledName { get { return ti_name; } }
        string vtbl_name; public string VTableMangledName { get { return vtbl_name; } }
        string static_name; public string StaticObjectMangledName { get { return static_name; } }

        public Layout(Assembler.TypeToCompile ttc, Assembler ass)
        { _ass = ass; CreateLayout(ttc, ass); }
        private Layout() { }

        public static Layout GetLayout(Assembler.TypeToCompile ttc, Assembler ass)
        {
            Layout l = new Layout();
            l._ass = ass;
            l.CreateLayout(ttc, ass);
            return l;
        }

        public void CreateLayout(Assembler.TypeToCompile ttc, Assembler ass)
        {
            _ass = ass;
            _ttc = ttc;

            LoadInterfaces(ttc, ass);
            ImplementInterfaces(ttc, ass);
            LayoutInterfaceFields(ttc, ass);
            LayoutInterfaces();

            string mangled_name = Mangler.Mangle(ttc, ass);
            static_name = mangled_name + "_S";
            ti_name = mangled_name + "_TI";
            vtbl_name = mangled_name + "_VT";
        }

        public static int GetClassSize(Assembler.TypeToCompile ttc, Assembler ass)
        {
            Layout l = new Layout();
            l._ass = ass;
            l._ttc = ttc;
            l.LoadInterfaces(ttc, ass);
            l.LayoutInterfaceFields(ttc, ass, false);

            int class_size = 0;
            foreach (ImplementedInterface i in l.Interfaces)
                class_size += i.ClassSize;
            return class_size;
        }

        public List<ImplementedInterface.ImplementedInterfaceField> Fields
        {
            get
            {
                List<ImplementedInterface.ImplementedInterfaceField> ret = new List<ImplementedInterface.ImplementedInterfaceField>();
                foreach (ImplementedInterface ii in Interfaces)
                    ret.AddRange(ii.Fields);
                return ret;
            }
        }
        public List<ImplementedInterface.ImplementedInterfaceField> StaticFields
        {
            get
            {
                List<ImplementedInterface.ImplementedInterfaceField> ret = new List<ImplementedInterface.ImplementedInterfaceField>();
                foreach (ImplementedInterface ii in Interfaces)
                    ret.AddRange(ii.Fields);
                return ret;
            }
        }
        public List<ImplementedInterface.ImplementedInterfaceMember> Members
        {
            get
            {
                List<ImplementedInterface.ImplementedInterfaceMember> ret = new List<ImplementedInterface.ImplementedInterfaceMember>();
                foreach (ImplementedInterface ii in Interfaces)
                    ret.AddRange(ii.Members);
                return ret;
            }
        }

        public ImplementedInterface GetInterface(Metadata.TypeDefRow tdr)
        {
            foreach (ImplementedInterface i in Interfaces)
            {
                if (i.Interface.InterfaceType.type == tdr)
                    return i;
                foreach (Assembler.TypeToCompile alias in i.InterfaceAliases)
                {
                    if (alias.type == tdr)
                        return i;
                }
            }
            return null;
        }
        public ImplementedInterface GetInterface(Assembler.TypeToCompile ttc, Assembler ass)
        {
            Signature.CompareOpts c_opts = new Signature.CompareOpts { CheckByRef = false };
            foreach (ImplementedInterface i in Interfaces)
            {
                if (Signature.TypeCompare(i.Interface.InterfaceType, ttc, ass, c_opts) == true)
                    return i;
                foreach (Assembler.TypeToCompile alias in i.InterfaceAliases)
                    if (Signature.TypeCompare(alias, ttc, ass, c_opts) == true)
                        return i;
            }
            return null;
        }

        public ImplementedInterface GetInterface(string mangled_name)
        {
            foreach (ImplementedInterface i in Interfaces)
            {
                if (i.ToString() == mangled_name)
                    return i;
            }
            return null;
        }

        private void LoadInterfaces(Assembler.TypeToCompile main_iface, Assembler ass)
        {
            Interfaces.Clear();

            Assembler.TypeToCompile cur_ttc = new Assembler.TypeToCompile { type = main_iface.type, tsig = main_iface.tsig };
            while (cur_ttc.type != null)
            {
                ImplementedInterface new_ii = new ImplementedInterface(GetGlobalInterface(cur_ttc, ass), this, ass);
                Interfaces.Add(new_ii);

                if ((cur_ttc.type.TypeName == "Array") && (cur_ttc.tsig.Type is Signature.ZeroBasedArray))
                    new_ii.InterfaceAliases.Add(Metadata.GetTTC("mscorlib", "System", "Array", ass));

                if (cur_ttc.type.Extends.Value != null)
                    cur_ttc = Metadata.GetTTC(cur_ttc.type.Extends, cur_ttc, ass);
                else
                    cur_ttc.type = null;
            }

            foreach (Metadata.TableIndex iface in main_iface.type.Interfaces)
                Interfaces.Add(new ImplementedInterface(GetGlobalInterface(Metadata.GetTTC(iface, main_iface, ass), ass), this, ass));
        }

        private void LayoutInterfaces()
        {
            int class_offset = 0;
            int vtable_offset = 0;
            int static_offset = 0;

            foreach (ImplementedInterface i in Interfaces)
            {
                i.OffsetToTop = class_offset;
                i.OffsetWithinVTable = vtable_offset;
                class_offset += i.ClassSize;
                vtable_offset += i.Interface.VTableSize;
            }

            foreach (ImplementedInterface.ImplementedInterfaceField iif in StaticFields)
            {
                iif.Offset = static_offset;
                static_offset += _ass.GetSizeOf(iif.Field.fsig);
            }

            class_size = class_offset;
            vtbl_size = vtable_offset;
            static_size = static_offset;

            foreach (ImplementedInterface i in Interfaces)
            {
                foreach (ImplementedInterface.ImplementedInterfaceMember iim in i.Members)
                {
                    if (iim.ToString() == "_N6_System_T4_Guid_S6_118468_M9_CompareTo_S8_2001081C (_N6_System_T4_Guid_S6_118468_M9_CompareTo_S8_2001081C)")
                    {
                        int sadhg = 0;
                    }
                    ImplementedInterface impl_in = GetInterface(iim.ImplementedIn, _ass);
                    if (impl_in != null)
                        iim.ThisAdjust = impl_in.OffsetWithinVTable - i.OffsetWithinVTable;
                    else if (iim.ImplementedMangledName != Assembler.PureVirtualSig)
                        throw new Exception("Interface not found");
                }
            }
        }

        private void LayoutInterfaceFields(Assembler.TypeToCompile main_iface, Assembler ass)
        { LayoutInterfaceFields(main_iface, ass, true); }

        private void LayoutInterfaceFields(Assembler.TypeToCompile main_iface, Assembler ass, bool layout_static)
        {
            int vtbl_counter = 0;
            foreach (ImplementedInterface i in Interfaces)
                LayoutInterfaceFields(i, main_iface, ass, ref vtbl_counter, layout_static);
        }

        private void LayoutInterfaceFields(ImplementedInterface i, Assembler.TypeToCompile main_iface, Assembler ass, ref int vtbl_counter, bool layout_static)
        {
            /* Perform the object and static class layout of the fields in interface */
            Metadata.TypeDefRow tdr = i.Interface.InterfaceType.type;
            Signature.Param tsig = Signature.ResolveGenericParam(i.Interface.InterfaceType.tsig, main_iface.tsig.Type, null, ass);
            //Signature.BaseOrComplexType tsig = Signature.ResolveGenericType(i.Interface.InterfaceType.tsig.Type, main_iface.tsig.Type, null, ass);
            int _offset = 0;
            int _staticoffset = 0;

            /* Add a field for the vtable pointer */
            Assembler.FieldToCompile vtblf = new Assembler.FieldToCompile
            {
                fsig = new Signature.Param(BaseType_Type.U),
                field = new Metadata.FieldRow { Flags = 0x0600, RowNumber = 0, Name = "__vtbl_" + vtbl_counter++.ToString() },
                definedin_tsig = tsig,
                definedin_type = tdr,
                memberof_tsig = main_iface.tsig,
                memberof_type = main_iface.type
            };
            i.Fields.Add(new ImplementedInterface.ImplementedInterfaceField(i, ass.GetSizeOf(vtblf.fsig)) { MangledName = Mangler.Mangle(vtblf, ass), Field = vtblf, Offset = _offset, Type = Field.FieldType.VTablePointer });
            _offset += ass.GetSizeOf(vtblf.fsig);

            /* If this is System.Object, add an object id */
            if(Signature.BCTCompare(tsig.Type, new Signature.BaseType(BaseType_Type.Object), ass))
            {
                Assembler.FieldToCompile oidf = new Assembler.FieldToCompile
                {
                    fsig = new Signature.Param(BaseType_Type.I4),
                    field = new Metadata.FieldRow { Flags = 0x601, RowNumber = 0, Name = "__object_id" },
                    definedin_tsig = tsig,
                    definedin_type = tdr,
                    memberof_tsig = main_iface.tsig,
                    memberof_type = main_iface.type
                };
                i.Fields.Add(new ImplementedInterface.ImplementedInterfaceField(i, ass.GetSizeOf(oidf.fsig)) { MangledName = Mangler.Mangle(oidf, ass), Field = oidf, Offset = _offset, Type = Field.FieldType.ObjectId });
                _offset += ass.GetSizeOf(oidf.fsig);
            }

            if (tsig.Type is Signature.BoxedType)
            {
                /* Boxed types have one member, namely m_value which contains an instance of the type which is boxed */
                Assembler.FieldToCompile ftc = new Assembler.FieldToCompile
                {
                    definedin_type = tdr,
                    definedin_tsig = tsig,
                    memberof_type = main_iface.type,
                    memberof_tsig = main_iface.tsig,
                    field = new Metadata.FieldRow { Name = "m_value" },
                    fsig = new Signature.Param(((Signature.BoxedType)tsig.Type).Type, ass)
                };

                ImplementedInterface.ImplementedInterfaceField iif = new ImplementedInterface.ImplementedInterfaceField(i, ass.GetSizeOf(ftc.fsig)) { Field = ftc, MangledName = Mangler.Mangle(ftc, ass) };
                iif.Offset = _offset;
                _offset += ass.GetSizeOf(ftc.fsig);
                i.Fields.Add(iif);
            }
            else
            {
                /* Other types are laid out as per the metadata */
                for (Metadata.TableIndex ti = tdr.FieldList; ti < Metadata.GetLastField(tdr.m, tdr); ti++)
                {
                    Metadata.FieldRow fr = ti.Value as Metadata.FieldRow;
                    Signature.Param fsig = Signature.ResolveGenericParam(Signature.ParseFieldSig(fr.m, fr.Signature).AsParam(ass), tsig.Type, null, ass);

                    if ((!layout_static) && (fr.IsStatic))
                        continue;

                    Assembler.FieldToCompile ftc = new Assembler.FieldToCompile
                    {
                        field = fr,
                        fsig = fsig,
                        definedin_type = tdr,
                        definedin_tsig = tsig,
                        memberof_type = main_iface.type,
                        memberof_tsig = main_iface.tsig
                    };

                    ImplementedInterface.ImplementedInterfaceField iif = new ImplementedInterface.ImplementedInterfaceField(i, ass.GetSizeOf(ftc.fsig)) { Field = ftc, MangledName = Mangler.Mangle(ftc, ass) };
                    int size = ass.GetSizeOf(ftc.fsig);

                    if (fr.IsStatic)
                    {
                        iif.Offset = _staticoffset;
                        _staticoffset += size;
                        i.StaticFields.Add(iif);
                        iif.Static = true;
                    }
                    else
                    {
                        iif.Offset = _offset;
                        _offset += size;
                        i.Fields.Add(iif);
                    }
                }
            }

            i._size = _offset;
            i._ssize = _staticoffset;
        }

        private void ImplementInterfaces(Assembler.TypeToCompile main_iface, Assembler ass)
        {
            foreach (ImplementedInterface i in Interfaces)
                ImplementInterface(i, main_iface, ass);
        }

        private void ImplementInterface(ImplementedInterface i, Assembler.TypeToCompile main_iface, Assembler ass)
        {
            foreach (ImplementedInterface.ImplementedInterfaceMember iim in i.Members)
            {
                if (iim.Type == Interface.InterfaceMember.InterfaceMemberType.Method)
                    ImplementMethod(iim, main_iface, ass);
            }
        }

        private void ImplementMethod(ImplementedInterface.ImplementedInterfaceMember iim, Assembler.TypeToCompile main_iface, Assembler ass)
        {
            /* First, decide if there is an explicit implementation specified in MethodImpl */
            foreach (Metadata.MethodImplRow mir in main_iface.type.m.Tables[(int)Metadata.TableId.MethodImpl])
            {
                if (Metadata.GetTypeDef(mir.Class.ToToken(), ass) == main_iface.type)
                {
                    Assembler.MethodToCompile mdecl = Metadata.GetMTC(mir.MethodDeclaration, main_iface, null, ass);
                    if (Signature.MethodCompare(mdecl, iim.MethodToCompile, ass))
                    {
                        /* NB the following from CIL II:22.27
                         * 
                         * Often MethodImpl is used in generic types, but MethodBody is a simple MethodDef owned by a TypeDef.  To identify the
                         *  correct signature of the implementing class we need to identify it by typedef in the interface list and get the
                         *  appropriate signature from there.  Point 6 tells us that the method will always be implemented in a base class or
                         *  interface and so its type will be in the interface list.
                         * 
                         * 6. The method indexed by MethodBody shall be a member of Class or some base class of Class
                            (MethodImpls do not allow compilers to ‘hook’ arbitrary method bodies) [ERROR]
                         * 9. MethodDeclaration shall index a method in the ancestor chain of Class (reached via its Extends
                            chain) or in the interface tree of Class (reached via its InterfaceImpl entries) [ERROR] */

                        Assembler.MethodToCompile mbody = Metadata.GetMTC(mir.MethodBody, main_iface, null, ass);
                        /* identify the typedef within the interface list */
                        bool found = false;
                        foreach (ImplementedInterface i in Interfaces)
                        {
                            if (i.Interface.InterfaceType.type == mbody.type)
                            {
                                mbody.tsig = i.Interface.InterfaceType.tsig.Type;
                                found = true;
                                break;
                            }
                        }
                        if (!found)
                            throw new Exception("MethodBody is not defined in this class (breaks CIL II:22.27 point 6)");

                        /* boxed type fudge */
                        if ((main_iface.tsig.Type is Signature.BoxedType) && (!(mbody.tsig is Signature.BoxedType)) && (Signature.BCTCompare(((Signature.BoxedType)main_iface.tsig.Type).Type, mbody.tsig, ass)))
                            mbody.tsig = new Signature.BoxedType(mbody.tsig);


                        iim.ImplementedMangledName = Mangler.Mangle(mbody, ass);
                        iim.ImplementedIn = new Assembler.TypeToCompile { type = mbody.type, tsig = new Signature.Param(mbody.tsig, ass) };
                        iim.Implementation = mbody;

                        /* zba fudge */
                        if (main_iface.tsig.Type is Signature.ZeroBasedArray)
                            iim.ImplementedIn.tsig = new Signature.Param(new Signature.ZeroBasedArray { ElemType = ((Signature.ZeroBasedArray)main_iface.tsig.Type).ElemType }, ass);
                        return;
                    }
                }
            }

            /* start at most derived and work backwards until an implementation is found */

            Assembler.TypeToCompile cur_ttc = new Assembler.TypeToCompile { type = main_iface.type, tsig = main_iface.tsig };
            while (cur_ttc.type != null)
            {
                for (Metadata.TableIndex meth = cur_ttc.type.MethodList; meth < Metadata.GetLastMethod(cur_ttc.type); meth++)
                {
                    Metadata.MethodDefRow mdr = Metadata.GetMethodDef(meth.ToToken(), ass);
                    if (!mdr.IsVirtual)
                        continue;

                    Signature.BaseMethod bmeth = Signature.ResolveGenericMember(Signature.ParseMethodSig(mdr), cur_ttc.tsig.Type, null, ass);
                    Assembler.MethodToCompile cur_mtc = new Assembler.MethodToCompile { meth = mdr, msig = bmeth, tsig = cur_ttc.tsig.Type, type = cur_ttc.type };

                    if (Signature.MethodCompare(cur_mtc, iim.MethodToCompile, ass))
                    {
                        if ((!mdr.IsAbstract) && (mdr.Body != null) && (mdr.Body.Body != null))
                        {
                            iim.ImplementedMangledName = Mangler.Mangle(cur_mtc, ass);
                            iim.ImplementedIn = cur_ttc;
                            iim.Implementation = cur_mtc;
                            return;
                        }
                    }
                }

                if (cur_ttc.type.Extends.Value != null)
                    cur_ttc = Metadata.GetTTC(cur_ttc.type.Extends, cur_ttc, ass);
                else
                    cur_ttc.type = null;
            }
        }

        public ImplementedInterface.ImplementedInterfaceField GetField(string mangled_name) { return GetField(mangled_name, false); }
        public ImplementedInterface.ImplementedInterfaceField GetField(string mangled_name, bool _static)
        {
            foreach (ImplementedInterface ii in Interfaces)
            {
                ImplementedInterface.ImplementedInterfaceField iif = ii.GetField(mangled_name, _static);
                if (iif != null)
                    return iif;
            }
            return null;
        }

        static Dictionary<string, Interface> GlobalInterfaces = new Dictionary<string, Interface>();
        static Interface GetGlobalInterface(Assembler.TypeToCompile iface, Assembler ass)
        {
            lock (GlobalInterfaces)
            {
                if (GlobalInterfaces.ContainsKey(Mangler.Mangle(iface, ass)))
                    return GlobalInterfaces[Mangler.Mangle(iface, ass)];

                Interface i = new Interface(iface, ass);
                GlobalInterfaces.Add(i.MangledName, i);
                return i;
            }
        }

        public class Interface
        {
            Assembler.TypeToCompile ttc;
            List<InterfaceMember> im = new List<InterfaceMember>();
            Assembler _ass;
            public Interface(Assembler ass) { _ass = ass; }

            public List<InterfaceMember> Members { get { return im; } }
            public string MangledName { get { return Mangler.Mangle(ttc, _ass); } }
            public Assembler.TypeToCompile InterfaceType { get { return ttc; } }

            int _size; public int VTableSize { get { return _size; } }

            public override string ToString()
            {
                return MangledName;
            }

            public InterfaceMember this[int index] { get { return im[index]; } set { im[index] = value; } }
            public InterfaceMember this[string mangled_name]
            {
                get
                {
                    foreach (InterfaceMember i in im)
                    {
                        if (i.MangledName == mangled_name)
                            return i;
                    }
                    throw new IndexOutOfRangeException(mangled_name);
               }
            }

            public Interface(Assembler.TypeToCompile ifacetype, Assembler ass) { ttc = ifacetype; CreateInterface(ifacetype, ass); _ass = ass; }

            public class InterfaceMember
            {
                Assembler _ass;
                protected Assembler.MethodToCompile mtc;
                public string MangledName { get { return Mangler.Mangle(mtc, _ass); } }
                public Assembler.MethodToCompile MethodToCompile { get { return mtc; } }
                protected int _offset;
                public int Offset { get { return _offset; } }
                public enum InterfaceMemberType { TypeInfoPointer, Method }

                protected InterfaceMemberType _type = InterfaceMemberType.Method; public InterfaceMemberType Type { get { return _type; } }

                public InterfaceMember(Assembler.MethodToCompile methodtocompile, int offset, Assembler ass) : this(ass) { _offset = offset; mtc = methodtocompile; _type = InterfaceMemberType.Method; }
                public static InterfaceMember TypeInfoPtr(Assembler ass) { return new InterfaceMember(ass) { _offset = 0, _type = InterfaceMemberType.TypeInfoPointer }; }
                protected InterfaceMember(Assembler ass) { _ass = ass; }

                public override string ToString()
                {
                    return MangledName;
                }
            }

            void CreateInterface(Assembler.TypeToCompile i, Assembler ass)
            {
                Metadata.TypeDefRow tdr = Metadata.GetTypeDef(i.type, ass);

                int curoffset = 0;
                im.Add(InterfaceMember.TypeInfoPtr(ass));
                curoffset += ass.GetSizeOfPointer();

                for (Metadata.TableIndex meth = tdr.MethodList; meth < Metadata.GetLastMethod(tdr); meth++)
                {
                    Metadata.MethodDefRow mdr = Metadata.GetMethodDef(meth.ToToken(), ass);
                    if (!mdr.IsVirtual)
                        continue;

                    Signature.BaseMethod msig = Signature.ResolveGenericMember(Signature.ParseMethodSig(mdr), i.tsig.Type, null, ass);                    

                    /* Only create a vtable entry for those methods marked newslot or those which haven't been defined in base classes */
                    
                    if ((mdr.IsNewSlot) || (!((tdr.Extends.Value != null) && (!DefinedInClass(Metadata.GetTTC(tdr.Extends, i, ass), mdr.Name, msig, true, ass)))))
                    {
                        im.Add(new InterfaceMember(new Assembler.MethodToCompile { meth = mdr, msig = msig, tsig = i.tsig.Type, type = i.type }, curoffset, ass));
                        curoffset += (2 * ass.GetSizeOfPointer());      /* Method pointer followed by this_adjust */
                    }
                }

                _size = curoffset;
            }

            private bool DefinedInClass(Assembler.TypeToCompile base_class, string meth_name, Signature.BaseMethod msig, bool virtual_only, Assembler ass)
            {
                for (Metadata.TableIndex meth = base_class.type.MethodList; meth < Metadata.GetLastMethod(base_class.type); meth++)
                {
                    Metadata.MethodDefRow mdr = Metadata.GetMethodDef(meth.ToToken(), ass);
                    if (virtual_only && (!mdr.IsVirtual))
                        continue;

                    if (mdr.Name == meth_name)
                    {
                        Signature.BaseMethod cur_msig = Signature.ResolveGenericMember(Signature.ParseMethodSig(mdr), base_class.tsig.Type, null, ass);

                        if(Signature.BaseMethodSigCompare(msig, cur_msig, ass))
                            return true;
                    }
                }
                return false;
            }
        }

        public class ImplementedInterface
        {
            Interface _iface;
            Layout l;

            public class ImplementedInterfaceMember : Interface.InterfaceMember
            {
                public string ImplementedMangledName = Assembler.PureVirtualSig;
                public int ThisAdjust;
                ImplementedInterface _ii;
                public Assembler.TypeToCompile ImplementedIn;
                public Assembler.MethodToCompile Implementation;

                public int OverallOffset { get { return _ii.OffsetWithinVTable + _offset; } }

                public ImplementedInterfaceMember(Interface.InterfaceMember imember, ImplementedInterface iiface, Assembler ass) : base(ass)
                {
                    _ii = iiface;
                    mtc = imember.MethodToCompile;
                    _offset = imember.Offset;
                    _type = imember.Type;
                }

                public override string ToString()
                {
                    if (_type == InterfaceMemberType.Method)
                        return MangledName + " (" + ImplementedMangledName + ")";
                    else
                        return "TypeInfoPointer";
                }
            }

            public class ImplementedInterfaceField
            {
                ImplementedInterface _ii; public ImplementedInterface Interface { get { return _ii; } }
                public string MangledName = "";
                int _offset; public int Offset { get { return _offset; } set { _offset = value; } }
                public Assembler.FieldToCompile Field;
                public Field.FieldType Type = Layout.Field.FieldType.Field;
                public bool Static = false;
                public int DataSize;

                public int OverallOffset { get { if(Static) return _offset; else return _ii.OffsetToTop + _offset; } }

                public ImplementedInterfaceField(ImplementedInterface iiface, int data_size) { _ii = iiface; DataSize = data_size; }
            }

            List<ImplementedInterfaceMember> iims = new List<ImplementedInterfaceMember>();
            public List<ImplementedInterfaceMember> Members { get { return iims; } }
            List<ImplementedInterfaceField> iifs = new List<ImplementedInterfaceField>();
            List<ImplementedInterfaceField> iisfs = new List<ImplementedInterfaceField>();
            public List<ImplementedInterfaceField> Fields { get { return iifs; } }
            public List<ImplementedInterfaceField> StaticFields { get { return iisfs; } }
            internal int _size = 0; internal int _ssize = 0;
            public int ClassSize { get { return _size; } }
            public int StaticClassSize { get { return _ssize; } }

            public Interface Interface { get { return _iface; } }
            public List<Assembler.TypeToCompile> InterfaceAliases = new List<Assembler.TypeToCompile>();

            public int OffsetToTop = 0;
            public int OffsetWithinVTable = 0;

            public override string ToString()
            {
                return _iface.ToString();
            }

            public ImplementedInterface(Interface iface, Layout layout, Assembler ass)
            {
                _iface = iface;
                l = layout;
                foreach (Interface.InterfaceMember im in iface.Members)
                    iims.Add(new ImplementedInterfaceMember(im, this, ass));
            }

            public ImplementedInterfaceField GetField(string mangled_name, bool _static)
            {
                List<ImplementedInterfaceField> flds = _static ? iisfs : iifs;
                foreach (ImplementedInterfaceField f in flds)
                {
                    if (mangled_name.StartsWith("_") && (f.MangledName == mangled_name))
                        return f;
                    else if (Signature.GetString(f.Field, l._ass) == mangled_name)
                        return f;
                }
                return null;
            }
            public ImplementedInterfaceField GetField(Assembler.FieldToCompile ftc, bool _static)
            {
                List<ImplementedInterfaceField> flds = _static ? iisfs : iifs;
                foreach (ImplementedInterfaceField f in flds)
                {
                    if (Signature.FieldCompare(ftc, f.Field, l._ass))
                        return f;
                }
                return null;
            }
            public ImplementedInterfaceMember GetMember(Assembler.MethodToCompile mtc)
            {
                foreach (ImplementedInterfaceMember m in Members)
                {
                    if (m.Type == Layout.Interface.InterfaceMember.InterfaceMemberType.Method)
                    {
                        if (Signature.MethodCompare(mtc, m.MethodToCompile, l._ass))
                            return m;
                    }
                }
                return null;
            }
        }

        public class Field
        {
            public enum FieldType { Field, VTablePointer, FiddleFactor, ObjectId };
        }
    }
}
